//! Nacos客户端配置

use serde::{Deserialize, Serialize};
use std::time::Duration;

/// Nacos客户端配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientConfig {
    /// Nacos服务器地址
    pub server_addr: String,
    /// 命名空间ID
    pub namespace: String,
    /// 连接超时时间（毫秒）
    pub connect_timeout: u64,
    /// 读取超时时间（毫秒）
    pub read_timeout: u64,
    /// 最大重试次数
    pub max_retries: u32,
    /// 重试间隔时间（毫秒）
    pub retry_interval: u64,
    /// 是否启用TLS
    pub enable_tls: bool,
    /// 认证信息
    pub auth_info: Option<AuthInfo>,
    /// 客户端元数据
    pub client_metadata: std::collections::HashMap<String, String>,
    /// 连接池最大连接数
    pub max_connections: usize,
    /// 连接池清理间隔（毫秒）
    pub pool_cleanup_interval: u64,
    /// 连接超时时间（毫秒）
    pub connection_idle_timeout: u64,
    /// 缓存最大条目数
    pub max_cache_entries: usize,
    /// 缓存过期时间（毫秒）
    pub cache_expire_time: u64,
}

/// 认证信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthInfo {
    /// 用户名
    pub username: String,
    /// 密码
    pub password: String,
    /// 访问密钥
    pub access_key: Option<String>,
    /// 密钥
    pub secret_key: Option<String>,
}

impl ClientConfig {
    /// 创建新的客户端配置
    pub fn new(server_addr: impl Into<String>) -> Self {
        Self {
            server_addr: server_addr.into(),
            namespace: "public".to_string(),
            connect_timeout: 3000,
            read_timeout: 5000,
            max_retries: 3,
            retry_interval: 1000,
            enable_tls: false,
            auth_info: None,
            client_metadata: std::collections::HashMap::new(),
            max_connections: 100,
            pool_cleanup_interval: 30000, // 30秒
            connection_idle_timeout: 60000, // 60秒
            max_cache_entries: 1000,
            cache_expire_time: 300000, // 5分钟
        }
    }

    /// 设置命名空间
    pub fn with_namespace(mut self, namespace: impl Into<String>) -> Self {
        self.namespace = namespace.into();
        self
    }

    /// 设置超时时间
    pub fn with_timeout(mut self, connect_timeout: u64, read_timeout: u64) -> Self {
        self.connect_timeout = connect_timeout;
        self.read_timeout = read_timeout;
        self
    }

    /// 设置重试策略
    pub fn with_retry(mut self, max_retries: u32, retry_interval: u64) -> Self {
        self.max_retries = max_retries;
        self.retry_interval = retry_interval;
        self
    }

    /// 启用TLS
    pub fn with_tls(mut self, enable_tls: bool) -> Self {
        self.enable_tls = enable_tls;
        self
    }

    /// 设置认证信息
    pub fn with_auth(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
        self.auth_info = Some(AuthInfo {
            username: username.into(),
            password: password.into(),
            access_key: None,
            secret_key: None,
        });
        self
    }

    /// 设置访问密钥认证
    pub fn with_access_key(mut self, access_key: impl Into<String>, secret_key: impl Into<String>) -> Self {
        if let Some(ref mut auth_info) = self.auth_info {
            auth_info.access_key = Some(access_key.into());
            auth_info.secret_key = Some(secret_key.into());
        } else {
            self.auth_info = Some(AuthInfo {
                username: String::new(),
                password: String::new(),
                access_key: Some(access_key.into()),
                secret_key: Some(secret_key.into()),
            });
        }
        self
    }

    /// 添加客户端元数据
    pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.client_metadata.insert(key.into(), value.into());
        self
    }

    /// 获取连接超时时间
    pub fn connect_timeout_duration(&self) -> Duration {
        Duration::from_millis(self.connect_timeout)
    }

    /// 获取读取超时时间
    pub fn read_timeout_duration(&self) -> Duration {
        Duration::from_millis(self.read_timeout)
    }

    /// 获取重试间隔时间
    pub fn retry_interval_duration(&self) -> Duration {
        Duration::from_millis(self.retry_interval)
    }

    /// 验证配置
    pub fn validate(&self) -> Result<(), crate::error::ClientError> {
        if self.server_addr.is_empty() {
            return Err(crate::error::ClientError::ConfigError(
                "Server address cannot be empty".to_string()
            ));
        }

        if self.connect_timeout == 0 {
            return Err(crate::error::ClientError::ConfigError(
                "Connect timeout must be greater than 0".to_string()
            ));
        }

        if self.read_timeout == 0 {
            return Err(crate::error::ClientError::ConfigError(
                "Read timeout must be greater than 0".to_string()
            ));
        }

        Ok(())
    }

    /// 获取完整的服务器URL
    pub fn server_url(&self) -> String {
        if self.enable_tls {
            if self.server_addr.starts_with("https://") {
                self.server_addr.clone()
            } else {
                format!("https://{}", self.server_addr)
            }
        } else {
            if self.server_addr.starts_with("http://") {
                self.server_addr.clone()
            } else {
                format!("http://{}", self.server_addr)
            }
        }
    }

    /// 获取认证头信息
    pub fn auth_headers(&self) -> Vec<(String, String)> {
        let mut headers = Vec::new();
        
        if let Some(ref auth_info) = self.auth_info {
            if !auth_info.username.is_empty() && !auth_info.password.is_empty() {
                let auth = format!("Basic {}", 
                    base64::encode(format!("{}:{}", auth_info.username, auth_info.password))
                );
                headers.push(("Authorization".to_string(), auth));
            }
            
            if let Some(ref access_key) = auth_info.access_key {
                headers.push(("Spas-AccessKey".to_string(), access_key.clone()));
            }
        }
        
        headers
    }
}

impl Default for ClientConfig {
    fn default() -> Self {
        Self::new("127.0.0.1:8848")
    }
}

/// 客户端配置构建器
#[derive(Debug)]
pub struct ClientConfigBuilder {
    config: ClientConfig,
}

impl ClientConfigBuilder {
    pub fn new(server_addr: impl Into<String>) -> Self {
        Self {
            config: ClientConfig::new(server_addr),
        }
    }

    pub fn namespace(mut self, namespace: impl Into<String>) -> Self {
        self.config.namespace = namespace.into();
        self
    }

    pub fn connect_timeout(mut self, timeout: u64) -> Self {
        self.config.connect_timeout = timeout;
        self
    }

    pub fn read_timeout(mut self, timeout: u64) -> Self {
        self.config.read_timeout = timeout;
        self
    }

    pub fn max_retries(mut self, retries: u32) -> Self {
        self.config.max_retries = retries;
        self
    }

    pub fn retry_interval(mut self, interval: u64) -> Self {
        self.config.retry_interval = interval;
        self
    }

    pub fn enable_tls(mut self, enable: bool) -> Self {
        self.config.enable_tls = enable;
        self
    }

    pub fn auth(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
        self.config.auth_info = Some(AuthInfo {
            username: username.into(),
            password: password.into(),
            access_key: None,
            secret_key: None,
        });
        self
    }

    pub fn access_key(mut self, access_key: impl Into<String>, secret_key: impl Into<String>) -> Self {
        self.config = self.config.with_access_key(access_key, secret_key);
        self
    }

    pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.config.client_metadata.insert(key.into(), value.into());
        self
    }

    pub fn build(self) -> ClientConfig {
        self.config
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_client_config_creation() {
        let config = ClientConfig::new("127.0.0.1:8848");
        assert_eq!(config.server_addr, "127.0.0.1:8848");
        assert_eq!(config.namespace, "public");
    }

    #[test]
    fn test_client_config_with_options() {
        let config = ClientConfig::new("localhost:8848")
            .with_namespace("test-namespace")
            .with_timeout(5000, 10000)
            .with_retry(5, 2000)
            .with_tls(true)
            .with_auth("admin", "password123");

        assert_eq!(config.server_addr, "localhost:8848");
        assert_eq!(config.namespace, "test-namespace");
        assert_eq!(config.connect_timeout, 5000);
        assert_eq!(config.read_timeout, 10000);
        assert_eq!(config.max_retries, 5);
        assert_eq!(config.retry_interval, 2000);
        assert!(config.enable_tls);
        assert!(config.auth_info.is_some());
    }

    #[test]
    fn test_client_config_server_url() {
        let config = ClientConfig::new("127.0.0.1:8848");
        assert_eq!(config.server_url(), "http://127.0.0.1:8848");

        let tls_config = ClientConfig::new("127.0.0.1:8848").with_tls(true);
        assert_eq!(tls_config.server_url(), "https://127.0.0.1:8848");
    }

    #[test]
    fn test_client_config_validation() {
        let valid_config = ClientConfig::new("127.0.0.1:8848");
        assert!(valid_config.validate().is_ok());

        let invalid_config = ClientConfig::new("");
        assert!(invalid_config.validate().is_err());

        let zero_timeout_config = ClientConfig {
            connect_timeout: 0,
            ..Default::default()
        };
        assert!(zero_timeout_config.validate().is_err());
    }

    #[test]
    fn test_client_config_builder() {
        let config = ClientConfigBuilder::new("127.0.0.1:8848")
            .namespace("test")
            .connect_timeout(3000)
            .read_timeout(5000)
            .max_retries(3)
            .retry_interval(1000)
            .enable_tls(true)
            .auth("user", "pass")
            .build();

        assert_eq!(config.server_addr, "127.0.0.1:8848");
        assert_eq!(config.namespace, "test");
        assert_eq!(config.connect_timeout, 3000);
        assert_eq!(config.read_timeout, 5000);
        assert_eq!(config.max_retries, 3);
        assert_eq!(config.retry_interval, 1000);
        assert!(config.enable_tls);
        assert!(config.auth_info.is_some());
    }

    #[test]
    fn test_auth_headers() {
        let config = ClientConfig::new("127.0.0.1:8848")
            .with_auth("admin", "password123");

        let headers = config.auth_headers();
        assert!(!headers.is_empty());
        assert!(headers[0].1.contains("Basic"));
    }
}